﻿using GameStructure.Types;
using Tao.OpenGl;

namespace GameStructure.Utilities
{
    public class Batch
    {
        const int MAX_VERTEX_NUMBER = 1000;
        const int VERTEX_DIMENSIONS = 3;
        const int COLOR_DIMENSIONS = 4;
        const int UV_DIMENSIONS = 2;
        private readonly Vector[] _vertexPositions = new Vector[MAX_VERTEX_NUMBER];
        private readonly Color[] _vertexColors = new Color[MAX_VERTEX_NUMBER];
        private readonly Point[] _vertexUVs = new Point[MAX_VERTEX_NUMBER];
        private int _batchSize;

        public void AddSprite(Sprite sprite)
        {
            // If the batch is full, draw it, empty and start again.
            if (sprite.VertexPositions.Length + _batchSize > MAX_VERTEX_NUMBER)
            {
                Draw();
            }

            // Add the current sprite vertices to the batch.
            for (var i = 0; i < sprite.VertexPositions.Length; i++)
            {
                _vertexPositions[_batchSize + i] = sprite.VertexPositions[i];
                _vertexColors[_batchSize + i] = sprite.VertexColors[i];
                _vertexUVs[_batchSize + i] = sprite.VertexUVs[i];
            }
            _batchSize += sprite.VertexPositions.Length;
        }

        public void Draw()
        {
            if (_batchSize == 0) return;

            SetupPointers();
            Gl.glDrawArrays(Gl.GL_TRIANGLES, 0, _batchSize);
            _batchSize = 0;
        }

        private void SetupPointers()
        {
            Gl.glEnableClientState(Gl.GL_COLOR_ARRAY);
            Gl.glEnableClientState(Gl.GL_VERTEX_ARRAY);
            Gl.glEnableClientState(Gl.GL_TEXTURE_COORD_ARRAY);

            Gl.glVertexPointer(VERTEX_DIMENSIONS, Gl.GL_DOUBLE, 0, _vertexPositions);
            Gl.glColorPointer(COLOR_DIMENSIONS, Gl.GL_FLOAT, 0, _vertexColors);
            Gl.glTexCoordPointer(UV_DIMENSIONS, Gl.GL_FLOAT, 0, _vertexUVs);
        }
    }
}